//    Travel US - For users of travel.usairways.com
//    intended for US Airways employees and their dependents
//    This app will help you track your flights and display
//    Availability, flight status and other non-rev info
//    Copyright (C) 2014  Renats Stozkovs
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

package com.bc004346.travelus;

import android.app.FragmentManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;

import com.bc004346.travelus.dataAccess.asyncTasks.SearchFlightsTaskFragment;
import com.bc004346.travelus.fragment.DatePickerFragment;
import com.bc004346.travelus.fragment.NavigationDrawerFragment;
import com.bc004346.travelus.model.Direction;
import com.bc004346.travelus.model.TravelUsUnavailableException;
import com.bc004346.travelus.model.domain.Flight;
import com.bc004346.travelus.model.domain.FlightSearchParams;
import com.bc004346.travelus.model.interfaces.IDatePickerCallback;
import com.bc004346.travelus.model.interfaces.ISearchFlightsCallback;
import com.bc004346.travelus.utility.Utility;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;

import static com.bc004346.travelus.model.domain.FlightSearchParams.Flag;
import static com.bc004346.travelus.utility.Utility.DATE;
import static com.bc004346.travelus.utility.Utility.DAY;
import static com.bc004346.travelus.utility.Utility.DEPARTURE;
import static com.bc004346.travelus.utility.Utility.DESTINATION;
import static com.bc004346.travelus.utility.Utility.FLIGHT_SEARCH_PARAMS;
import static com.bc004346.travelus.utility.Utility.IS_ONE_WAY;
import static com.bc004346.travelus.utility.Utility.ORIGIN;
import static com.bc004346.travelus.utility.Utility.RETURN;
import static com.bc004346.travelus.utility.Utility.SEARCH_TASK_TAG;
import static com.bc004346.travelus.utility.Utility.SHORT_DATE;
import static com.bc004346.travelus.utility.Utility.flightsSelection;
import static com.bc004346.travelus.utility.Utility.log;
import static com.bc004346.travelus.utility.Utility.onActivityStart;
import static com.bc004346.travelus.utility.Utility.onActivityStop;

/**
 * Created by Renats on 3/9/14.
 * Book Travel
 */
public class BookTravelActivity extends FragmentActivity
        implements ISearchFlightsCallback,
        LoaderCallbacks<Cursor>, IDatePickerCallback {

    private static final String DIALOG_DATE = "date";

    //<editor-fold desc="Members">

    private NavigationDrawerFragment mNavigationDrawer;
    private FragmentManager mFragmentManager;
    private ProgressBar mProgressBar;
    private RadioButton mRadioButtonOneWay;
    private EditText mEditTextDestination;
    private EditText mEditTextOrigin;
    private TextView mTextViewMessage;
    private Button mButtonDepartureDate;
    private Button mButtonReturnDate;
    private Button mButtonSearch;
    private Uri uri;

    private Date mDepartureDate;
    private Date mReturnDate;

    //</editor-fold>
    //<editor-fold desc="Properties">

    public String getEditTextOrigin() {
        Editable x = mEditTextOrigin.getText();
        return x == null ? "" : x.toString();
    }

    public String getEditTextDestination() {
        Editable x = mEditTextDestination.getText();
        return x == null ? "" : x.toString();
    }

    public boolean getRadioButtonOneWay() {
        return mRadioButtonOneWay.isChecked();
    }

    //</editor-fold>
    //<editor-fold desc="Overrides">

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(getBaseContext(), uri, null, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        if (data.moveToFirst())
            mEditTextOrigin.setText(data.getString(data.getColumnIndex(data.getColumnName(1))));
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // not implemented
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_book_travel);

        setupUI();
    }

    @Override
    protected void onStart() {
        super.onStart();
        onActivityStart(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        onActivityStop(this);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mNavigationDrawer.syncState();
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        mNavigationDrawer.handleOnPrepareOptionsMenu(menu);
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        mNavigationDrawer.syncState();
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        mNavigationDrawer.handleOnOptionsItemSelected(item);
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onSearchPostExecute(ArrayList<Flight> flights, Exception e) {
        try {
            mProgressBar.setVisibility(View.INVISIBLE);
            mButtonSearch.setText(getString(R.string.bookTravel_ButtonSearchText));
            mButtonSearch.setEnabled(true);
            removeSearchFragment();

            if (e != null) {
                if (e.getClass() == TravelUsUnavailableException.class) {
                    log(e);
                    mTextViewMessage.setText("Travel US is having problems processing your request. It may be down right now");
                } else {
                    mTextViewMessage.setText(e.getMessage());
                    log(e, this);
                }
                return;
            }

            if (flights == null || flights.size() == 0) {
                mTextViewMessage.setText(getString(R.string.common_no_flights_found));
                return;
            }

            flightsSelection = flights;

            Intent intent = new Intent(this, FlightSelectionActivity.class);
            intent.putExtra(ORIGIN, getEditTextOrigin());
            intent.putExtra(DESTINATION, getEditTextDestination());
            intent.putExtra(DEPARTURE, DATE.format(mDepartureDate));
            intent.putExtra(RETURN, DATE.format(mReturnDate == null ? mDepartureDate : mReturnDate));
            intent.putExtra(IS_ONE_WAY, getRadioButtonOneWay());
            startActivity(intent);

            finish();

        } catch (Exception ex) {
            mTextViewMessage.setText(ex.getMessage());
            log(ex, this);
        }
    }

    @Override
    public void onDatePicked(Date date, Direction direction) {
        switch (direction) {
            case Inbound:
                mReturnDate = date;
                mButtonReturnDate.setText(Utility.SHORT_DATE.format(date));
                break;
            case Outbound:
                mDepartureDate = date;
                mButtonDepartureDate.setText(Utility.SHORT_DATE.format(date));
                break;
        }
    }

    //</editor-fold>
    //<editor-fold desc="Private Methods">

    private void setupUI() {
        try {
            mNavigationDrawer = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.activity_fragment_drawer);
            if (mNavigationDrawer != null)
                mNavigationDrawer.init();

            mProgressBar = (ProgressBar) findViewById(R.id.bookTravel_progressBar);
            mEditTextOrigin = (EditText) findViewById(R.id.bookTravel_editTextOrigin);
            mEditTextDestination = (EditText) findViewById(R.id.bookTravel_editTextDestination);
            mButtonDepartureDate = (Button) findViewById(R.id.bookTravel_editTextDeparture);
            mButtonReturnDate = (Button) findViewById(R.id.bookTravel_editTextReturn);
            RadioGroup radioGroup = (RadioGroup) findViewById(R.id.bookTravel_radioButtonGroup);
            mRadioButtonOneWay = (RadioButton) findViewById(R.id.bookTravel_radioButtonOneWay);
            mButtonSearch = (Button) findViewById(R.id.bookTravel_buttonSearch);
            Button buttonLookupOrigin = (Button) findViewById(R.id.bookTravel_buttonLookupOrigin);
            Button buttonLookupDestination = (Button) findViewById(R.id.bookTravel_buttonLookupDestination);
            mTextViewMessage = (TextView) findViewById(R.id.bookTravel_textViewMessage);
            mFragmentManager = getFragmentManager();


            radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(RadioGroup group, int checkedId) {
                    mButtonReturnDate.setVisibility(mRadioButtonOneWay.isChecked() ? View.GONE : View.VISIBLE);
                }
            });
            mButtonSearch.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (isInputValid()) searchFlights();
                }
            });
            buttonLookupOrigin.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    lookupAirports(Flag.Origin);
                }
            });
            buttonLookupDestination.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    lookupAirports(Flag.Destination);
                }
            });
            mButtonDepartureDate.setOnClickListener(new View.OnClickListener() {
                public void onClick(View view) {
                    android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
                    DatePickerFragment dialog =
                            DatePickerFragment.newInstance(mDepartureDate == null ? new Date() : mDepartureDate, Direction.Outbound);
                    dialog.show(fm, DIALOG_DATE);
                }
            });

            mButtonReturnDate.setOnClickListener(new View.OnClickListener() {
                public void onClick(View view) {
                    android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
                    DatePickerFragment dialog =
                            DatePickerFragment.newInstance(mReturnDate == null ? new Date() : mReturnDate, Direction.Inbound);
                    dialog.show(fm, DIALOG_DATE);
                }
            });

            Intent originalIntent = getIntent();
            FlightSearchParams params =
                    (FlightSearchParams) originalIntent.getSerializableExtra(FLIGHT_SEARCH_PARAMS);
            if (params != null) {
                DateFormat df = SHORT_DATE;
                mEditTextOrigin.setText(params.getOrigin());
                mEditTextDestination.setText(params.getDestination());
                mRadioButtonOneWay.setChecked(params.isOneWay());
                mButtonDepartureDate.setText(params.getDeparture() == null ? "" : df.format(params.getDeparture()));
                mButtonReturnDate.setText(params.getReturn() == null ? "" : df.format(params.getReturn()));
            }

        } catch (Exception e) {
            if (mTextViewMessage != null) mTextViewMessage.setText(e.getMessage());
            log(e, this);
        }
    }

    private void lookupAirports(Flag flag) {
        Bundle appData = new Bundle();
        FlightSearchParams params = new FlightSearchParams();
        params.setOrigin(getEditTextOrigin());
        params.setDestination(getEditTextDestination());
        params.setIsOneWay(getRadioButtonOneWay());
        params.setDeparture(mDepartureDate);
        params.setReturn(mReturnDate);
        params.setAirportLookupToken(flag);
        appData.putSerializable(FLIGHT_SEARCH_PARAMS, params);
        startSearch(null, false, appData, false);
    }

    private boolean isInputValid() {

        StringBuilder message = new StringBuilder();

        try {
            if (getEditTextOrigin().length() != 3)
                message.append("Origin should be 3 characters long\n\r");

            if (getEditTextDestination().length() != 3)
                message.append("Destination should be 3 characters long\n\r");

            if (mDepartureDate == null)
                message.append("Unable to parse Departure Date\n\r");
            else if (mDepartureDate.getTime() < new Date().getTime() - DAY)
                message.append("Departure Date cannot be in the past\n\r");

            if (!getRadioButtonOneWay() && mReturnDate == null)
                message.append("Unable to parse Return Date\n\r");
            else if (!getRadioButtonOneWay() && mReturnDate.getTime() < new Date().getTime() - DAY)
                message.append("Return Date cannot be in the past\n\r");
            else if (!getRadioButtonOneWay() && mDepartureDate.getTime() > mReturnDate.getTime())
                message.append("Departure Date cannot be greater than Return Date\n\r");

            if (message.length() == 0)
                return true;

            mTextViewMessage.setText(message.toString());
        } catch (Exception e) {
            mTextViewMessage.setText(e.getMessage());
            log(e, this);
        }
        return false;
    }

    private void searchFlights() {
        try {
            mProgressBar.setVisibility(View.VISIBLE);
            mButtonSearch.setText(getString(R.string.bookTravel_ButtonSearchTextAlt));
            mButtonSearch.setEnabled(false);
            SearchFlightsTaskFragment fragment =
                    (SearchFlightsTaskFragment) mFragmentManager.findFragmentByTag(SEARCH_TASK_TAG);
            if (fragment == null) {
                FlightSearchParams params = new FlightSearchParams();
                params.setOrigin(getEditTextOrigin());
                params.setDestination(getEditTextDestination());
                params.setDeparture(mDepartureDate);
                params.setReturn(mReturnDate);
                params.setIsOneWay(getRadioButtonOneWay());
                fragment = SearchFlightsTaskFragment.newInstance(params, false);
                mFragmentManager.beginTransaction().add(fragment, SEARCH_TASK_TAG).commitAllowingStateLoss();
            }
        } catch (Exception e) {
            mProgressBar.setVisibility(View.INVISIBLE);
            mTextViewMessage.setText(e.getMessage());
            log(e, this);
        }
    }

    private void removeSearchFragment() {
        try {
            SearchFlightsTaskFragment fragment =
                    (SearchFlightsTaskFragment) getFragmentManager().findFragmentByTag(SEARCH_TASK_TAG);
            if (fragment != null)
                mFragmentManager.beginTransaction().remove(fragment).commitAllowingStateLoss();
        } catch (Exception e) {
            mTextViewMessage.setText(e.getMessage());
            log(e, this);
        }
    }

    //</editor-fold>
}
